#ifndef __SIGMANAGER_H__
#define __SIGMANAGER_H__

/**
   The SigManager has two responsibilities:
 
   1. Keep track of what signals the user has registered handlers for
   when coming in and out of real mode.  When goto_sim is called we
   loop through the sigaction's reported to us by the OS and see
   which, if any, the user has registered a handler for.  If the user
   has registered a handler, we save that in our own array of
   handlers, and register our own signal handler with the OS.  When we
   go to real mode from sim mode, we loop through and re-register the
   user's signal handlers with the OS.
   
   2. Receive signals from the OS and send them to the appropriate
   processor.  In the case of an asynchronous signal, we schedule it
   for later execution.  The Simulator will tell us to run any
   scheduled signals every cycle. In the case of a synchronous signal,
   we give the info to the Simulator, and do a long jump into
   Simulator::run(), where it will send the signal to the Processor
   that was running and continue doing its thing.
*/

#include <setjmp.h>
#include <signal.h>
#include <ucontext.h>

#include "base/Processor.h"
#include "base/signals/SigContext.h"
#include "base/simapi.h"
#include "util/Logger.h"

#if defined(__linux__) || defined(_AIX)
extern const char *sys_signame[NSIG];
#endif

extern sigjmp_buf sigjmpEnv;

extern "C" void signalHandler(int signum, siginfo_t* siginfo, ucontext_t* sigcontext);
extern "C" void defaultSigSegvHandler (int signum, siginfo_t* siginfo, ucontext_t* sigcontext);
extern "C" void noop_uint(unsigned);
extern "C" const char* getSigName(int signum);

extern Logger* signalLog;

class SigManager
{
public:
    // overloaded to force use of CALLOC/FREE
    NEW_DELETE_OPERATORS_H(SigManager,NoSuper);
    SigManager ();
    ~SigManager ();
    void checkHandlerRegistration ();
    void restoreHandlerRegistration ();

    int registerHandler (int signum, const struct sigaction* act, struct sigaction* oldact);
    void* getHandler (int signum);

    sigset_t* getSigMask (int signum);

    void runScheduledSignal ();
    void runScheduledThreadSignal ();
    void invokeSignalHandler (int signum, Processor* P, void* extra, size_t extraSize);
    void invokeSignalHandler (int signum, siginfo_t* siginfo, ucontext_t* sigcontext);
    static bool isSynchronous (int signum);

    void checkSignal (int signum);
    void scheduleSignal (int signum, SigContext* sigContext);

    void scheduleThreadSignal (int procID, int signum, SigContext* sigContext);

private:
    struct SigRecord {
        bool scheduled;
        int occurances;
        SigContext* sigContext;
    } records[MAX_SIG_NUM];
    struct SigProcRecord {
        bool scheduled; 
        SigContext* sigContext;
    } procRecords[MAX_NUM_CPUS];

    int regd_signum[MAX_SIG_NUM];
    int numRegisteredHandlers;
    struct sigaction* handlers[MAX_SIG_NUM];

    int signal_alarm_frequency;

    stack_t signal_alternate_stack;

    int schedulingHead;
    int procSchedulingHead;
    int numScheduledProcSignal;
};
#endif // __SIGMANAGER_H__
